package com.leizi.igym.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leizi.igym.constant.EquipConstant;
import com.leizi.igym.domain.Equip;
import com.leizi.igym.domain.EquipCategory;
import com.leizi.igym.domain.Region;
import com.leizi.igym.dto.EquipAddDTO;
import com.leizi.igym.dto.EquipDTO;
import com.leizi.igym.dto.EquipPageQueryDTO;
import com.leizi.igym.enums.ReturnCodeEnum;
import com.leizi.igym.exception.BusinessException;
import com.leizi.igym.mapper.EquipMapper;
import com.leizi.igym.service.CategoryService;
import com.leizi.igym.service.EquipCategoryService;
import com.leizi.igym.service.EquipService;
import com.leizi.igym.service.RegionService;
import com.leizi.igym.util.RedisUtils;
import com.leizi.igym.utils.ThrowUtils;
import com.leizi.igym.vo.EquipVO;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.List;
import java.util.Objects;

/**
 * @author PC
 * @description 针对表【t_equip(健身器材表)】的数据库操作Service实现
 * @createDate 2024-04-09 10:04:21
 */
@Service
public class EquipServiceImpl extends ServiceImpl<EquipMapper, Equip>
        implements EquipService {

    @Resource
    private CategoryService categoryService;

    @Resource
    private EquipMapper equipMapper;

    @Resource
    private RegionService regionService;

    @Resource
    private EquipCategoryService equipCategoryService;

    /**
     * 新增器械
     *
     * @param dto
     * @return: boolean
     **/
    @Override
    @Transactional
    public boolean saveEquip(EquipAddDTO dto) {
        if (Objects.isNull(dto)) {
            throw new BusinessException(ReturnCodeEnum.PARAMS_ERROR);
        }

        String equipName = dto.getEquipName();
        String intro = dto.getIntro();
        String picture = dto.getPicture();
        Long regionId = dto.getRegionId();
        List<Long> partList = dto.getPartList();
        LocalDate purchaseTime = dto.getPurchaseTime();

        if (Objects.isNull(purchaseTime)) {
            throw new BusinessException(ReturnCodeEnum.PARAMS_ERROR);
        }

        List<Long> allId = categoryService.getAllId();
        if (CollectionUtil.isEmpty(allId)) {
            throw new BusinessException(ReturnCodeEnum.SYSTEM_ERROR, "无分类消息");
        }

        // 判断参数合法性
        if (StringUtils.isAnyBlank(equipName, picture, intro)) {
            throw new BusinessException(ReturnCodeEnum.PARAMS_ERROR);
        }

        if (!CollectionUtil.containsAll(allId, partList)) {
            throw new BusinessException(ReturnCodeEnum.PARAMS_ERROR, "锻炼部分为空或不合法！");
        }

        if (Objects.isNull(regionId) || regionId <= 0) {
            throw new BusinessException(ReturnCodeEnum.PARAMS_ERROR);
        }

        Region dbRegion = regionService.getById(regionId);
        if (Objects.isNull(dbRegion)) {
            throw new BusinessException(ReturnCodeEnum.PARAMS_ERROR, "没有找到相应区域！");
        }

        // 构造插入对象
        Equip equip = new Equip();
        BeanUtils.copyProperties(dto, equip);
        // 默认管理端添加是已认证了
        Integer result = this.getBaseMapper().insert(equip);
        if (null == result || result < 1) {
            return false;
        }
        Long equipId = equip.getId();

        // 向教练-擅长方向库插入信息
        List<EquipCategory> trainerCategoryList = partList.stream().map(part -> {
            EquipCategory equipCategory = new EquipCategory();
            equipCategory.setEquipId(equipId);
            equipCategory.setCategoryId(part);
            return equipCategory;
        }).toList();

        boolean bool = equipCategoryService.saveBatch(trainerCategoryList);

        return bool;
    }


    /**
     * 根据器械id删除器械
     *
     * @param id
     * @return: boolean
     **/
    @Override
    @Transactional
    public boolean removeEquipById(Long id) {
        ThrowUtils.throwIf(Objects.isNull(id) || id <= 0, ReturnCodeEnum.PARAMS_ERROR);

        // 先删除器械锻炼部位库记录
        QueryWrapper<EquipCategory> qw = new QueryWrapper<>();
        qw.eq("equip_id", id);
        boolean bool = equipCategoryService.remove(qw);
        if (!bool) {
            return false;
        }

        // 删除教练
        Integer result = this.getBaseMapper().deleteById(id);
        return null != result && result >= 1;
    }

    /**
     * 批量删除器械信息
     *
     * @param ids
     * @return: boolean
     **/
    @Override
    public boolean deleteEquipBatch(List<Long> ids) {
        ThrowUtils.throwIf(CollectionUtil.isEmpty(ids), ReturnCodeEnum.PARAMS_ERROR);
        List<EquipCategory> trainerCategoryList = ids.stream().map(id -> {
            EquipCategory equipCategory = new EquipCategory();
            equipCategory.setEquipId(id);
            return equipCategory;
        }).toList();
        boolean bool = equipCategoryService.removeBatchByIds(trainerCategoryList);
        if (!bool) {
            return false;
        }
        Integer result = this.getBaseMapper().deleteBatchIds(ids);
        return null != result && result >= 1;
    }

    /**
     * 修改器械信息
     *
     * @param dto
     * @return: boolean
     **/
    @Override
    @Transactional
    public boolean updateEquip(EquipDTO dto) {
        ThrowUtils.throwIf(Objects.isNull(dto), ReturnCodeEnum.PARAMS_ERROR);
        ThrowUtils.throwIf(Objects.isNull(dto.getPurchaseTime()), ReturnCodeEnum.PARAMS_ERROR);
        Equip equip = new Equip();
        BeanUtils.copyProperties(dto, equip);

        // 更新教练信息
        Integer result = this.getBaseMapper().updateById(equip);
        if (Objects.isNull(result) || result <= 0) {
            return false;
        }

        // 更新器械锻炼部分信息。采取先删在新增的策略
        // 检验id合法性
        List<Long> partList = dto.getPartList();
        if (Objects.isNull(partList)) {
            return true;
        }

        List<Long> categoryAllId = categoryService.getAllId();
        boolean allIn = CollectionUtil.containsAll(categoryAllId, partList);
        if (!allIn) {
            throw new BusinessException(ReturnCodeEnum.PARAMS_ERROR, "器械锻炼部位传参有误！");
        }
        Long trainerId = equip.getId();
        List<EquipCategory> equipCategories = partList.stream().map(part -> {
            EquipCategory equipCategory = new EquipCategory();
            equipCategory.setEquipId(trainerId);
            equipCategory.setCategoryId(part);
            return equipCategory;
        }).toList();

        QueryWrapper<EquipCategory> qw = new QueryWrapper<>();
        qw.eq("equip_id",dto.getId());
        equipCategoryService.remove(qw);
        boolean bool = equipCategoryService.saveBatch(equipCategories);

        return bool;
    }

    /**
     * 分页查询器械信息
     *
     * @param dto
     * @return: cPage<com.leizi.igym.vo.EquipVO>
     **/
    @Override
    public Page<EquipVO> getEquipPage(EquipPageQueryDTO dto) {

        ThrowUtils.throwIf(Objects.isNull(dto), ReturnCodeEnum.PARAMS_ERROR);

        // 创建条件查询器
        Long regionId = dto.getRegionId();
        LocalDate beginTime = dto.getBeginTime();
        LocalDate endTime = dto.getEndTime();
        Long part = dto.getPart();

        if (ObjectUtils.allNotNull(beginTime ,endTime) && !endTime.isAfter(beginTime)){
            throw new BusinessException(ReturnCodeEnum.PARAMS_ERROR);
        }

        if (Objects.nonNull(regionId) && regionId <= 0) {
            throw new BusinessException(ReturnCodeEnum.PARAMS_ERROR);
        }

        if (part !=null && part >= 0){
            List<Long> ids = equipCategoryService.getEquipIdByPart(part);
            if (ids == null || ids.size() == 0) {
                return null;
            }
            dto.setIds(ids);
        }

        // QueryWrapper<EquipVO> qw = new QueryWrapper<>();
        //
        // qw.eq(Objects.nonNull(regionId),"region_id", regionId);
        // qw.like(StringUtils.isNotBlank(equipName), "tr_name", equipName);
        // qw.eq(EquipConstant.EQUIP_STATUS_LIST.contains(status), "status", status);
        //
        // DateQWUtils.getDateQWForEquip(qw, beginTime, endTime);
        // Page<EquipVO> voPage = equipMapper.selectPageWithPart(new Page<>(dto.getCurrent(),
        //         dto.getPageSize()), qw);

        Page<EquipVO> voPage1 = equipMapper.selectPageWithPartByDTO(new Page<>(dto.getCurrent(),
                dto.getPageSize()), dto);

        return voPage1;
    }

    /**
     * 管理端根据id查询器械信息
     *
     * @param id
     * @return: com.leizi.igym.vo.EquipVO
     **/
    @Override
    public EquipVO getByIdWithPart(Long id) {
        ThrowUtils.throwIf(Objects.isNull(id) || id <= 0,
                ReturnCodeEnum.PARAMS_ERROR);

        EquipVO equipVO = null;
        equipVO = RedisUtils.get("equip::"+id, EquipVO.class);
        if (Objects.nonNull(equipVO)){
            return equipVO;
        }
        equipVO = equipMapper.selectByIdWithPart(id);
        RedisUtils.set("equip::"+id,equipVO);
        return equipVO;
    }

    @Override
    public boolean modifyStatus(Long id, Integer status) {
        // 校验参数id是否合法
        ThrowUtils.throwIf(Objects.isNull(id) || id < 0, ReturnCodeEnum.PARAMS_ERROR);
        // 校验isIdentify参数是否合法
        ThrowUtils.throwIf(Objects.isNull(status) ||
                !EquipConstant.EQUIP_STATUS_LIST.contains(status), ReturnCodeEnum.PARAMS_ERROR);
        Equip dbEquip = this.getBaseMapper().selectById(id);
        ThrowUtils.throwIf(Objects.isNull(dbEquip), ReturnCodeEnum.PARAMS_ERROR);
        ThrowUtils.throwIf(dbEquip.getStatus() == status, ReturnCodeEnum.IDENTIFY_ERROR);
        dbEquip.setStatus(status);
        return this.getBaseMapper().updateById(dbEquip) > 0;
    }

    @Override
    public List<EquipVO> getAllWithPart() {
        List<EquipVO> equipVOList = null;
        equipVOList = RedisUtils.get("ALL_EQUIP",List.class);
        if (Objects.nonNull(equipVOList)){
            return equipVOList;
        }

        equipVOList = this.getBaseMapper().selectWithPart();
        RedisUtils.set("ALL_EQUIP",equipVOList);
        return equipVOList;
    }

}




